"""
    create by IAmFiveHigh on 2023/8/17
"""
import math
from typing import List, Union

from .__globals import is_zero, is_equal


class Vector:
    def __init__(self, lst: List[Union[int, float]]):
        self._values = list(lst)

    @classmethod
    def zero(cls, dimension: int) -> 'Vector':
        return cls([0] * dimension)

    def under_list(self) -> List[Union[int, float]]:
        # 返回复制一份底层列表
        return self._values[:]

    def __str__(self):
        return "({})".format(','.join(str(a) for a in self._values))

    def __repr__(self):
        return "Vector: ({})".format(self._values)

    def __len__(self):
        return len(self._values)

    def __getitem__(self, index: int) -> Union[int, float]:
        if index >= len(self):
            raise ValueError(f"Error: index({index}) 超过了 vector({self}) 的长度{len(self)}")
        return self._values[index]

    def __iter__(self):
        # 返回向量的迭代器
        return self._values.__iter__()

    def __add__(self, other) -> 'Vector':
        # 向量加法
        self._guard_length_same(other)
        return Vector([a + b for a, b in zip(self, other)])

    def __sub__(self, other) -> 'Vector':
        # 向量减法
        self._guard_length_same(other)
        return Vector([a - b for a, b in zip(self, other)])

    def __mul__(self, other) -> 'Vector':
        # 向量左乘
        return Vector([a * other for a in self])

    def __rmul__(self, other) -> 'Vector':
        # 向量右乘
        return self.__mul__(other)

    def __truediv__(self, other) -> 'Vector':
        # 向量除法
        if is_zero(other):
            raise ZeroDivisionError(f"Error: {self} / {other} 除数不能为零")
        return (1 / other) * self

    def __neg__(self) -> 'Vector':
        return self * -1

    def __eq__(self, other: 'Vector'):
        if len(self) != len(other):
            return False
        return all([is_equal(a, b) for a, b in zip(self.under_list(), other.under_list())])

    def __neq__(self, other: 'Vector'):
        return not(self == other)

    def norm(self) -> float:
        # 向量的模
        return math.sqrt(sum(e ** 2 for e in self._values))

    def normalize(self) -> 'Vector':
        # 向量的单位向量
        n = self.norm()
        if is_zero(n):
            raise ZeroDivisionError(f"Error: {self} / {n} 求单位向量时除数不能为零")
        return Vector(self._values) / n

    def dot(self, another_vector) -> float:
        # 向量点乘向量 va * vb = |va||vb|cos(va)(vb)
        self._guard_length_same(another_vector)
        return sum(a * b for a, b in zip(self, another_vector))

    def _guard_length_same(self, other):
        if len(other) != len(self):
            raise Exception(f"Error: 向量{self} 与 向量{other}维度应相等")
